/**
 * 数据缓存管理工具类
 * 支持内存缓存、本地存储缓存、过期时间管理等功能
 */

interface CacheItem<T = any> {
  data: T;
  timestamp: number;
  expireTime?: number;
  version?: string;
}

interface CacheOptions {
  expireTime?: number; // 过期时间（毫秒）
  version?: string; // 数据版本
  storage?: 'memory' | 'local' | 'session'; // 存储类型
  compress?: boolean; // 是否压缩
}

interface SyncOptions {
  force?: boolean; // 强制同步
  background?: boolean; // 后台同步
  retry?: number; // 重试次数
  timeout?: number; // 超时时间
}

class CacheManager {
  private static instance: CacheManager;
  private memoryCache = new Map<string, CacheItem>();
  private syncQueue = new Set<string>();
  private syncPromises = new Map<string, Promise<any>>();
  private maxMemorySize = 100; // 内存缓存最大条目数
  private defaultExpireTime = 5 * 60 * 1000; // 默认5分钟过期
  
  static getInstance(): CacheManager {
    if (!CacheManager.instance) {
      CacheManager.instance = new CacheManager();
    }
    return CacheManager.instance;
  }
  
  /**
   * 设置缓存
   */
  set<T>(key: string, data: T, options: CacheOptions = {}): void {
    const {
      expireTime = this.defaultExpireTime,
      version = '1.0',
      storage = 'memory',
      compress = false
    } = options;
    
    const cacheItem: CacheItem<T> = {
      data: compress ? this.compress(data) : data,
      timestamp: Date.now(),
      expireTime: expireTime > 0 ? Date.now() + expireTime : undefined,
      version
    };
    
    switch (storage) {
      case 'memory':
        this.setMemoryCache(key, cacheItem);
        break;
      case 'local':
        this.setLocalStorage(key, cacheItem);
        break;
      case 'session':
        this.setSessionStorage(key, cacheItem);
        break;
    }
  }
  
  /**
   * 获取缓存
   */
  get<T>(key: string, storage: 'memory' | 'local' | 'session' = 'memory'): T | null {
    let cacheItem: CacheItem<T> | null = null;
    
    switch (storage) {
      case 'memory':
        cacheItem = this.getMemoryCache(key);
        break;
      case 'local':
        cacheItem = this.getLocalStorage(key);
        break;
      case 'session':
        cacheItem = this.getSessionStorage(key);
        break;
    }
    
    if (!cacheItem) {
      return null;
    }
    
    // 检查是否过期
    if (this.isExpired(cacheItem)) {
      this.remove(key, storage);
      return null;
    }
    
    return cacheItem.data;
  }
  
  /**
   * 获取或设置缓存（如果不存在则通过回调获取数据）
   */
  async getOrSet<T>(
    key: string,
    fetcher: () => Promise<T>,
    options: CacheOptions = {}
  ): Promise<T> {
    const { storage = 'memory' } = options;
    
    // 先尝试从缓存获取
    const cached = this.get<T>(key, storage);
    if (cached !== null) {
      return cached;
    }
    
    // 检查是否正在同步
    if (this.syncPromises.has(key)) {
      return this.syncPromises.get(key)!;
    }
    
    // 创建同步Promise
    const syncPromise = this.fetchAndCache(key, fetcher, options);
    this.syncPromises.set(key, syncPromise);
    
    try {
      const data = await syncPromise;
      return data;
    } finally {
      this.syncPromises.delete(key);
    }
  }
  
  /**
   * 获取数据并缓存
   */
  private async fetchAndCache<T>(
    key: string,
    fetcher: () => Promise<T>,
    options: CacheOptions
  ): Promise<T> {
    try {
      const data = await fetcher();
      this.set(key, data, options);
      return data;
    } catch (error) {
      // 如果获取失败，尝试返回过期的缓存数据
      const expiredCache = this.getExpiredCache<T>(key, options.storage);
      if (expiredCache) {
        console.warn(`Using expired cache for key: ${key}`);
        return expiredCache;
      }
      throw error;
    }
  }
  
  /**
   * 移除缓存
   */
  remove(key: string, storage: 'memory' | 'local' | 'session' = 'memory'): void {
    switch (storage) {
      case 'memory':
        this.memoryCache.delete(key);
        break;
      case 'local':
        if (typeof uni !== 'undefined') {
          uni.removeStorageSync(key);
        } else if (typeof localStorage !== 'undefined') {
          localStorage.removeItem(key);
        }
        break;
      case 'session':
        if (typeof sessionStorage !== 'undefined') {
          sessionStorage.removeItem(key);
        }
        break;
    }
  }
  
  /**
   * 清空缓存
   */
  clear(storage: 'memory' | 'local' | 'session' = 'memory'): void {
    switch (storage) {
      case 'memory':
        this.memoryCache.clear();
        break;
      case 'local':
        if (typeof uni !== 'undefined') {
          uni.clearStorageSync();
        } else if (typeof localStorage !== 'undefined') {
          localStorage.clear();
        }
        break;
      case 'session':
        if (typeof sessionStorage !== 'undefined') {
          sessionStorage.clear();
        }
        break;
    }
  }
  
  /**
   * 同步数据
   */
  async sync<T>(
    key: string,
    fetcher: () => Promise<T>,
    options: SyncOptions & CacheOptions = {}
  ): Promise<T> {
    const {
      force = false,
      background = false,
      retry = 3,
      timeout = 10000,
      ...cacheOptions
    } = options;
    
    // 如果不是强制同步，先检查缓存
    if (!force) {
      const cached = this.get<T>(key, cacheOptions.storage);
      if (cached !== null) {
        // 后台同步
        if (background) {
          this.backgroundSync(key, fetcher, cacheOptions, retry);
        }
        return cached;
      }
    }
    
    // 同步数据
    return this.syncWithRetry(key, fetcher, cacheOptions, retry, timeout);
  }
  
  /**
   * 后台同步
   */
  private async backgroundSync<T>(
    key: string,
    fetcher: () => Promise<T>,
    options: CacheOptions,
    retry: number
  ): Promise<void> {
    try {
      const data = await this.syncWithRetry(key, fetcher, options, retry);
      console.log(`Background sync completed for key: ${key}`);
    } catch (error) {
      console.warn(`Background sync failed for key: ${key}`, error);
    }
  }
  
  /**
   * 带重试的同步
   */
  private async syncWithRetry<T>(
    key: string,
    fetcher: () => Promise<T>,
    options: CacheOptions,
    retry: number,
    timeout?: number
  ): Promise<T> {
    let lastError: any;
    
    for (let i = 0; i <= retry; i++) {
      try {
        const fetchPromise = fetcher();
        
        // 添加超时控制
        const data = timeout
          ? await Promise.race([
              fetchPromise,
              new Promise<never>((_, reject) =>
                setTimeout(() => reject(new Error('Timeout')), timeout)
              )
            ])
          : await fetchPromise;
        
        this.set(key, data, options);
        return data;
      } catch (error) {
        lastError = error;
        
        // 最后一次重试失败
        if (i === retry) {
          break;
        }
        
        // 等待后重试
        await this.delay(Math.pow(2, i) * 1000); // 指数退避
      }
    }
    
    throw lastError;
  }
  
  /**
   * 批量同步
   */
  async batchSync<T>(
    items: Array<{
      key: string;
      fetcher: () => Promise<T>;
      options?: SyncOptions & CacheOptions;
    }>
  ): Promise<Array<{ key: string; data?: T; error?: any }>> {
    const results = await Promise.allSettled(
      items.map(async (item) => {
        try {
          const data = await this.sync(item.key, item.fetcher, item.options);
          return { key: item.key, data };
        } catch (error) {
          return { key: item.key, error };
        }
      })
    );
    
    return results.map((result, index) => {
      if (result.status === 'fulfilled') {
        return result.value;
      } else {
        return { key: items[index].key, error: result.reason };
      }
    });
  }
  
  /**
   * 预加载数据
   */
  async preload<T>(
    key: string,
    fetcher: () => Promise<T>,
    options: CacheOptions = {}
  ): Promise<void> {
    try {
      await this.getOrSet(key, fetcher, options);
    } catch (error) {
      console.warn(`Preload failed for key: ${key}`, error);
    }
  }
  
  /**
   * 获取缓存统计信息
   */
  getStats(): {
    memorySize: number;
    memoryKeys: string[];
    expiredKeys: string[];
  } {
    const expiredKeys: string[] = [];
    const validKeys: string[] = [];
    
    this.memoryCache.forEach((item, key) => {
      if (this.isExpired(item)) {
        expiredKeys.push(key);
      } else {
        validKeys.push(key);
      }
    });
    
    return {
      memorySize: this.memoryCache.size,
      memoryKeys: validKeys,
      expiredKeys
    };
  }
  
  /**
   * 清理过期缓存
   */
  cleanup(): void {
    const expiredKeys: string[] = [];
    
    this.memoryCache.forEach((item, key) => {
      if (this.isExpired(item)) {
        expiredKeys.push(key);
      }
    });
    
    expiredKeys.forEach(key => {
      this.memoryCache.delete(key);
    });
    
    console.log(`Cleaned up ${expiredKeys.length} expired cache items`);
  }
  
  // 私有方法
  
  private setMemoryCache<T>(key: string, item: CacheItem<T>): void {
    // 检查内存缓存大小限制
    if (this.memoryCache.size >= this.maxMemorySize) {
      // 删除最旧的缓存项
      const oldestKey = this.memoryCache.keys().next().value;
      if (oldestKey) {
        this.memoryCache.delete(oldestKey);
      }
    }
    
    this.memoryCache.set(key, item);
  }
  
  private getMemoryCache<T>(key: string): CacheItem<T> | null {
    return this.memoryCache.get(key) || null;
  }
  
  private setLocalStorage<T>(key: string, item: CacheItem<T>): void {
    try {
      const serialized = JSON.stringify(item);
      
      if (typeof uni !== 'undefined') {
        uni.setStorageSync(key, serialized);
      } else if (typeof localStorage !== 'undefined') {
        localStorage.setItem(key, serialized);
      }
    } catch (error) {
      console.warn(`Failed to set local storage for key: ${key}`, error);
    }
  }
  
  private getLocalStorage<T>(key: string): CacheItem<T> | null {
    try {
      let serialized: string | null = null;
      
      if (typeof uni !== 'undefined') {
        serialized = uni.getStorageSync(key);
      } else if (typeof localStorage !== 'undefined') {
        serialized = localStorage.getItem(key);
      }
      
      return serialized ? JSON.parse(serialized) : null;
    } catch (error) {
      console.warn(`Failed to get local storage for key: ${key}`, error);
      return null;
    }
  }
  
  private setSessionStorage<T>(key: string, item: CacheItem<T>): void {
    try {
      if (typeof sessionStorage !== 'undefined') {
        sessionStorage.setItem(key, JSON.stringify(item));
      }
    } catch (error) {
      console.warn(`Failed to set session storage for key: ${key}`, error);
    }
  }
  
  private getSessionStorage<T>(key: string): CacheItem<T> | null {
    try {
      if (typeof sessionStorage !== 'undefined') {
        const serialized = sessionStorage.getItem(key);
        return serialized ? JSON.parse(serialized) : null;
      }
    } catch (error) {
      console.warn(`Failed to get session storage for key: ${key}`, error);
    }
    return null;
  }
  
  private isExpired<T>(item: CacheItem<T>): boolean {
    return item.expireTime ? Date.now() > item.expireTime : false;
  }
  
  private getExpiredCache<T>(key: string, storage: 'memory' | 'local' | 'session' = 'memory'): T | null {
    let cacheItem: CacheItem<T> | null = null;
    
    switch (storage) {
      case 'memory':
        cacheItem = this.getMemoryCache(key);
        break;
      case 'local':
        cacheItem = this.getLocalStorage(key);
        break;
      case 'session':
        cacheItem = this.getSessionStorage(key);
        break;
    }
    
    return cacheItem ? cacheItem.data : null;
  }
  
  private compress<T>(data: T): T {
    // 简单的压缩实现，实际项目中可以使用更复杂的压缩算法
    try {
      const jsonString = JSON.stringify(data);
      // 这里可以添加实际的压缩逻辑
      return JSON.parse(jsonString);
    } catch {
      return data;
    }
  }
  
  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// 导出单例实例
export const cacheManager = CacheManager.getInstance();

// 导出便捷方法
export const cache = {
  set: <T>(key: string, data: T, options?: CacheOptions) => cacheManager.set(key, data, options),
  get: <T>(key: string, storage?: 'memory' | 'local' | 'session') => cacheManager.get<T>(key, storage),
  getOrSet: <T>(key: string, fetcher: () => Promise<T>, options?: CacheOptions) => cacheManager.getOrSet(key, fetcher, options),
  remove: (key: string, storage?: 'memory' | 'local' | 'session') => cacheManager.remove(key, storage),
  clear: (storage?: 'memory' | 'local' | 'session') => cacheManager.clear(storage),
  sync: <T>(key: string, fetcher: () => Promise<T>, options?: SyncOptions & CacheOptions) => cacheManager.sync(key, fetcher, options),
  preload: <T>(key: string, fetcher: () => Promise<T>, options?: CacheOptions) => cacheManager.preload(key, fetcher, options),
  cleanup: () => cacheManager.cleanup(),
  stats: () => cacheManager.getStats()
};

// 导出类型
export type { CacheOptions, SyncOptions, CacheItem };

// 定期清理过期缓存
if (typeof setInterval !== 'undefined') {
  setInterval(() => {
    cacheManager.cleanup();
  }, 10 * 60 * 1000); // 每10分钟清理一次
}